﻿using Abp.Application.Services;
using Abp.Domain.Repositories;
using Abp.Web.Models;
using Batman.Cms.Core.Tools;
using Batman.Jianbei.Forum.Config;
using Batman.Jianbei.Forum.Controllers.Posts;
using Batman.Jianbei.Forum.Core.Domains.Dicts;
using Batman.Jianbei.Forum.Core.Domains.Posts;
using Microsoft.EntityFrameworkCore;
using Omu.ValueInjecter;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Batman.Core;
using System.Linq;
using System.Security.Principal;
using System.Text.RegularExpressions;
using Batman.Cms.Core.Models.Mvc;
using Batman.Jianbei.Forum.Areas.Forum.Converts;
using Batman.Jianbei.Forum.Areas.Forum.Filters;
using Batman.Jianbei.Forum.Areas.Forum.Responses;
using Batman.Jianbei.Forum.Core.Domains.Socials;
using Batman.Jianbei.Forum.Core.Enums;
using Batman.Jianbei.Forum.Repositories.Mongo;
using Batman.Jianbei.Forum.Services.Posts;
using Batman.Jianbei.Forum.Services.Posts.Dtos;
using Microsoft.EntityFrameworkCore.Internal;
using MongoDB.Driver;

namespace Batman.Jianbei.Forum.Services
{
    public class PostService : ApplicationService
    {
        public UpYunTool UpYunTool { get; set; }

        public IRepository<Topic, string> topicRepo { get; set; }

        public IRepository<Post, string> postRepo { get; set; }

        public IRepository<PostTint, string> postTintRepo { get; set; }

        public IRepository<PostComment, string> CommentRepo { get; set; }

        public PostTintCollection PostLikeCollection { get; set; }

        public IRepository<Follow, String> FollowRepo { get; set; }

        public AccessRepository AccessRepo { get; set; }


        public async Task<AjaxResponse> WeixinH5PublishAsync(WeixinH5PublishInput model, string wxUserId)
        {
            var topic = await topicRepo.GetAll().AsNoTracking().FirstOrDefaultAsync(t => t.Id == model.TopicId);
            if (topic == null)
                return new AjaxResponse { Success = false, Error = new ErrorInfo("话题不存在或已失效") };

            var post = new Post();
            post.Imgs = new List<PostImg>();

            if (model.ServerIds != null && model.ServerIds.Count > 0)
            {
                foreach (var serverId in model.ServerIds)
                {
                    using (var mm = new MemoryStream())
                    {
                        await Senparc.Weixin.MP.AdvancedAPIs.MediaApi.GetAsync(WeixinSetting.weixin_app_id, serverId,
                            mm);

                        var postImg = new PostImg(mm);
                        post.Imgs.Add(postImg);
                    }
                }
            }


            // 去除头尾的p html
            model.PostContent = Regex.Replace(model.PostContent, "^<p>", string.Empty);
            model.PostContent = Regex.Replace(model.PostContent, "</p>$", string.Empty);

            post.InjectFrom(model);
            post.CreateAt = DateTime.Now;
            post.WxUserId = wxUserId;
            //post.UserId = Request User.GetUserId();

            post.Status = Core.Enums.PostStatus.published;

            var newPost = postRepo.Insert(post);
            return new AjaxResponse { Success = true, Result = newPost };
        }

        /// <summary>
        /// 获取我点赞/收藏的文章
        /// </summary>
        /// <param name="page"></param>
        /// <param name="wxUID"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<PostFlowItem>> GetMyTintPostAsync(PagedResultRequestDto page, string wxUID,
            PostTintType tintType)
        {
            var postQuery = postRepo.GetQuery().Where(t => t.Status == PostStatus.published);

            postQuery = postQuery.Include(t => t.WxUser).Include(t => t.Imgs).Include(t => t.Topic)
                .ThenInclude(t => t.Partition);

            var postTintQuery = postTintRepo.GetQuery().Where(t => t.Type == tintType && t.WxUserId == wxUID);


            var postNewQuery = postTintQuery.OrderByDescending(t => t.CreateAt).Skip(page.SkipCount)
                .Take(page.MaxResultCount);

            var items = await postNewQuery
                .Join(postQuery, tint => tint.PostId, post => post.Id, (tint, post) => post.ToPostFlowItem())
                .ToListAsync();
            int total = await postTintQuery.CountAsync();

            List<string> postIds = items.Select(t => t.PostId).ToList();


            List<NameValueDto<int>> counts = CommentRepo.GetAll().AsNoTracking()
                .Where(t => items.Any(s => s.PostId == t.PostId))
                .GroupBy(t => t.PostId)
                .Select(t => new NameValueDto<int>(t.Key, t.Count()))
                .ToList();


            items.ForEach(t =>
            {
                NameValueDto<int> match = counts.FirstOrDefault(s => s.Name == t.PostId);
                if (match != null) t.CommentCount = match.Value;
            });

            List<PostTintCount> likeCounts = PostLikeCollection.GetTintCounts(postIds, wxUID);

            foreach (PostFlowItem item in items)
            {
                PostTintCount postTintCount = likeCounts.FirstOrDefault(t => t.PostId == item.PostId);
                if (postTintCount == null) continue;

                item.IsLike = postTintCount.IsLike;
                item.LikeCount = postTintCount.LinkCount;
                item.IsFavorite = postTintCount.IsFavorite;
            }


            return new PagedResultDto<PostFlowItem>(total, items);
        }

        /// <summary>
        /// 获取文章
        /// </summary>
        /// <param name="page">分页</param>
        /// <param name="filter"></param>
        /// <param name="wxUId"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<PostFlowItem>> GetPostAsync(PagedResultRequestDto page, PostFilter filter,
            string wxUId)
        {
            var post_query = postRepo.GetAll().AsNoTracking().AsQueryable();

            post_query = post_query.Include(t => t.WxUser).Include(t => t.Imgs).Include(t => t.Topic)
                .ThenInclude(t => t.Partition).AsQueryable();

            if (!string.IsNullOrEmpty(filter.CreateBy))
            {
                post_query = post_query.Where(t => t.WxUserId == filter.CreateBy);
            }

            // 排除帖子
            if (filter.ExcludePost != null && filter.ExcludePost.Count > 0)
            {
                if (filter.ExcludePost.Count >= 1000) return new PagedResultDto<PostFlowItem>(); // 超过1000返回空数据
                post_query = post_query.Where(t => !filter.ExcludePost.Contains(t.Id));
            }

            if (!string.IsNullOrEmpty(filter.PartitionId))
            {
                post_query = post_query.Where(t => t.Topic.PartitionId == filter.PartitionId);
            }

            if (filter.MaxCreateAt.HasValue)
            {
                post_query = post_query.Where(t => t.CreateAt <= filter.MaxCreateAt.Value);
            }

            if (filter.MinCreateAt.HasValue)
            {
                post_query = post_query.Where(t => t.CreateAt >= filter.MinCreateAt.Value);
            }

            post_query = post_query.Where(t => t.Status == PostStatus.published).OrderByDescending(t => t.CreateAt);

            int total = await post_query.CountAsync();
            List<PostFlowItem> items = await post_query.Skip(page.SkipCount).Take(page.MaxResultCount)
                .Select(t => t.ToPostFlowItem()).ToListAsync();

            List<string> postIds = items.Select(t => t.PostId).ToList();
            List<PostTintCount> likeCounts = PostLikeCollection.GetTintCounts(postIds, wxUId);

            foreach (PostFlowItem item in items)
            {
                PostTintCount postTintCount = likeCounts.FirstOrDefault(t => t.PostId == item.PostId);
                if (postTintCount == null) continue;

                item.IsLike = postTintCount.IsLike;
                item.LikeCount = postTintCount.LinkCount;
                item.IsFavorite = postTintCount.IsFavorite;
            }


            List<NameValueDto<int>> counts = await CommentRepo.GetAll().AsNoTracking()
                .Where(t => items.Any(s => s.PostId == t.PostId))
                .GroupBy(t => t.PostId)
                .Select(t => new NameValueDto<int>(t.Key, t.Count()))
                .ToListAsync();

            var wxUIds = items.Select(t => t.WxUId).ToList();

            var myFollowings = await this.FilterMyFollowing(wxUIds, wxUId);

            if (filter.DisplayAccess)
            {
                var mf = Builders<Access>.Filter.Where(t => postIds.Contains(t.PostId));
                var accesses = AccessRepo.Collection.Aggregate().Match(mf)
                    .Group(t => t.PostId, s => new NameValueDto<int>(s.Key, s.Count()))
                    .ToList();
                items.ForEach(t =>
                {
                    // 访问量
                    var accessCount = accesses.FirstOrDefault(s => s.Name == t.PostId);
                    t.AccessCount = accessCount.Value;
                });
            }

            items.ForEach(t =>
            {
                NameValueDto<int> match = counts.FirstOrDefault(s => s.Name == t.PostId);
                if (match != null) t.CommentCount = match.Value;

                t.Followed = myFollowings.Any(s => s == t.WxUId);
            });


            return new PagedResultDto<PostFlowItem>(total, items);
        }

        /// <summary>
        /// 判断传入的微信用户id是不是我关注的人
        /// </summary>
        /// <param name="wxUIdList"></param>
        /// <param name="currentWxUId"></param>
        /// <returns>我关注的人的微信用户id</returns>
        private async Task<List<string>> FilterMyFollowing(List<string> wxUIdList, string currentWxUId)
        {
            // 我关注的
            var query = FollowRepo.GetQuery().Where(t => t.FollowBy == currentWxUId);
            // 我关注的列表选出传入的用户列表
            query = query.Where(t => wxUIdList.Contains(t.WxUserId));
            var result = await query.Select(t => t.WxUserId).ToListAsync();

            return result;
        }

        /// <summary>
        /// 作者删除帖子
        /// </summary>
        /// <returns></returns>
        public ResponseBase TrashPostByOwnerAsync(string postId, string currentWxUId)
        {
            var postExist = postRepo.GetQuery().Any(t => t.Id == postId && t.WxUserId == currentWxUId);

            if (!postExist) return new ResponseBase(false, "帖子不存在，或您无权删除");

            postRepo.Update(postId, t => t.Status = PostStatus.trashed);

            return new ResponseBase();
        }
    }
}